/*Copyright (C) 2009 Careil Baptiste

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "Error.h"
#include "Network.h"
#include <errno.h>
#include <string.h>

CSLP_UDPSOCKET DLL_IMPEXP CSLP_InitUDPSocket()
{
#ifdef WIN32
  InitWSA();
#endif /* WIN32 */
  return socket(AF_INET, SOCK_DGRAM, 0);
}


int DLL_IMPEXP CSLP_Bind(CSLP_UDPSOCKET serverSock, unsigned short port)
{
  SOCKADDR_IN sockIn;
  sockIn.sin_addr.s_addr = htonl(INADDR_ANY);
  sockIn.sin_family = AF_INET;
  sockIn.sin_port = htons(port);
  memset(sockIn.sin_zero, 0, 8);
  return bind(serverSock, (SOCKADDR*)(&sockIn), sizeof(sockIn));
}

CSLP_NETWORK_ERROR DLL_IMPEXP CSLP_SendTo(CSLP_UDPSOCKET sock, const void* data, size_t dataLen, unsigned long IP, unsigned short port)
{
  CSLP_NETWORK_ERROR retVal = NONE;
  SOCKADDR_IN sockIn;
  sockIn.sin_addr.s_addr = IP;
  sockIn.sin_port = htons(port);
  sockIn.sin_family = AF_INET;
  memset(sockIn.sin_zero, 0, 8);

  if (sendto(sock, data, dataLen, MSG_NOSIGNAL, (SOCKADDR*)(&sockIn), sizeof(sockIn)) == -1)
    {
      retVal = CSLP_GetLastNetworkError();
    }
  return retVal;
}

CSLP_NETWORK_ERROR DLL_IMPEXP CSLP_ReceiveFrom(CSLP_UDPSOCKET sock, void* data, size_t dataLen, size_t* bytesWrite, unsigned long* IP, unsigned short* port)
{
  CSLP_NETWORK_ERROR retVal = NONE;
  int bytesReceive;
  SOCKADDR_IN sockIn;
  socklen_t sockInLen = sizeof(sockIn);

  if (data == NULL || bytesWrite == NULL || IP == NULL || port == NULL)
    {
      return ERROR;
    }

  bytesReceive = recvfrom(sock, data, dataLen, 0, (SOCKADDR*)(&sockIn), &sockInLen);
  if(bytesReceive == -1)
    {
      retVal = CSLP_GetLastNetworkError();
    }
  else
    {
      *bytesWrite = bytesReceive;
      *IP = sockIn.sin_addr.s_addr;
      *port = htons(sockIn.sin_port);
    }
  return retVal;
}

void DLL_IMPEXP CSLP_CloseUDPSocket(CSLP_UDPSOCKET sock)
{
#ifdef WIN32
  if (closesocket((SOCKET)(sock)) == 0)
    {
      CloseWSA();
    }
#else /* WIN32 */
  close((int)(sock));
#endif /* !WIN32 */
}
